<?php
	/*
		Gatherer Content Managment System
		Copyright © 2007-2010 by Eric Hokanson
		Last changed on $LastChangedDate: 2009-12-17 15:34:16 -0700 (Thu, 17 Dec 2009) $
		Revision $Revision: 26 $
		Requires Smarty (www.smarty.net) and the Zend Framework (framework.zend.com)

		This program is free software: you can redistribute it and/or modify
		it under the terms of the GNU General Public License as published by
		the Free Software Foundation, either version 3 of the License, or
		(at your option) any later version.
		
		This program is distributed in the hope that it will be useful,
		but WITHOUT ANY WARRANTY; without even the implied warranty of
		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
		GNU General Public License for more details.
		
		You should have received a copy of the GNU General Public License
		along with this program.  If not, see <http://www.gnu.org/licenses/>.
	*/

	define('GCMS_VERSION', '1.2');

	require_once 'dbconfig.php';
	require_once 'Zend/Feed.php';
	require_once 'Zend/Loader.php';
	require_once 'Zend/Session/Namespace.php';
	require_once 'Zend/Translate.php';
	require_once 'Zend/Version.php';
	require_once 'Zend/View.php';
	require_once 'Zend/View/Helper/Doctype.php';
	require_once 'Zend_View_Smarty.php';

	/**
	 * Converts an RFC date to a UNIX timestamp
	 * 
	 * @param string $rfc A date in a RFC format
	 * @param string $type A PHP RFC date constant that $rfc is in
	 * @return int Unix timestamp
	 */
	function dateToTimestamp($rfc, $type = DATE_RFC3339) {
		if ($type == DATE_RFC3339 || $type == DATE_ATOM) {
			$rfc = strtr($rfc, 'Z', '+00:00');
			list($date, $time) = explode('T', $rfc);
			list($year, $month, $day) = explode('-', $date);
			list($hour, $min, $sec) = explode(':', $time);
			return mktime($hour, $min, substr($sec, 0, 2), $month, $day, $year);
		}
		elseif ($type == DATE_RFC822 || $type == DATE_RSS) {
			$aMonth = array('Jan'=>1, 'Feb'=>2, 'Mar'=>3, 'Apr'=>4, 'May'=>5,
							'Jun'=>6, 'Jul'=>7, 'Aug'=>8, 'Sep'=>9, 'Oct'=>10,
							'Nov'=>11, 'Dec'=>12);
			list($date, $year, $time) = preg_split('/ (\d{4}) /', $rfc, 3, PREG_SPLIT_DELIM_CAPTURE);
			list( , $day, $month) = explode(" ", $date);
			list($hour, $min, $sec) = explode(":", $time);
			$month = $aMonth[$month];
			return mktime($hour, $min, substr($sec, 0, 2), $month, $day, $year);
		}
		return 0;
	}

	/**
	 * Cleans feeds by stripping most tags
	 *
	 * @param string $raw Raw HTML from feeds that needs to be cleaned.
	 * @return string Cleaned HTML
	 */
	function cleanFeed($raw) {
		$search = array('@<script[^>]*?>.*?</script>@si',  // Strip out javascript
					   '@<style[^>]*?>.*?</style>@siU',    // Strip style tags properly
					   '@<p>(.*)Read more of this story</a> at Slashdot(.*)>$@s'  // Hack to clean Slashdot code
		);
		$raw = preg_replace($search, '', $raw);
		$raw = strip_tags($raw, '<p><br><b><strong><i><a><ul><li><img><object><param><embed>');
		return $raw;
	}
	
	/**
	 * Builds a clickable tag list.
	 *
	 * @param string $list A list of comma seperated tags.
	 * @return string A list of tags enclosed by <a> tags
	 */
	function tag_builder($list) {
		if (empty($list))
			$list = $GLOBALS['translate']->_('[Uncategorized]');
		$tag_array = explode(',', $list);
		foreach($tag_array as $v)
			$tag_links .= "<a href=\"index.php?mod=tags&amp;term=" . trim($v) . "\">" . trim($v) . "</a>, ";
		return rtrim($tag_links,', ');
	}
	
	/**
	 * Allows translation in Smarty templates.
	 *
	 * @param string $string The string to be translated.
	 * @return string The translated string.
	 */
	function smarty_translate($string) {
		return $GLOBALS['translate']->_($string);
	}
	
	// Some stupid hosts have magic_quotes_gpc turned on with no way to turn them off
	if (get_magic_quotes_gpc()) {
		foreach ($_POST as $key => $value)
			$_POST[$key] = stripslashes($value);
	}
	
	// Our translations
	$translate = new Zend_Translate('array', './languages/english.php', 'en');
	//$translate->addTranslation('./languages/spanish.php', 'es');

	// Session namespace
	$authNamespace = new Zend_Session_Namespace('gcmsadmin');
	if (!isset($authNamespace->admin))
		$authNamespace->admin = false;
	
	// Load our config and check for sane values
	try {
		$config = $db->fetchRow("SELECT * FROM config");
		if (empty($config['rootuser']) || empty($config['rootpassword']))
			throw new Exception();
	} catch (Exception $e) {
		header("Location: ./install/index.php");
		exit;
	}

	// Setup our view (Smarty wrapper)
	$view = new Zend_View_Smarty('./themes/' . $config['sitetheme'] . '/templates',
								 array('plugins_dir' => array('plugins', './filters'), 'caching' => 0));
	$view->getEngine()->register_modifier('translate', 'smarty_translate');
	$doctypeHelper = new Zend_View_Helper_Doctype();
	$doctypeHelper->doctype('XHTML1_STRICT');
	$headers = new Zend_View();
	
	// Convenience for admin access
	if (count($_GET) == 1 && isset($_GET['admin']))
		$_GET['mod'] = 'admin';

	// Include then load modules
	$blacklist = array('template');
	$moddirlist = scandir('./modules');
	foreach ($moddirlist as $v) {
		if (is_dir("./modules/".$v) && preg_match('/^([A-Z]|[a-z]|_)/',$v) && !in_array($v, $blacklist)) {
			include_once "./modules/$v/$v.php";
			$modloaded[] = $v;
		}
	}
	foreach ($modloaded as $v) {
		$logger->log('Loading module: ' . $v, Zend_Log::DEBUG);
		if (isset($_GET['mod']) && $_GET['mod'] == $v && function_exists($v.'_onLoad')) {
			try {
				call_user_func($v.'_onLoad', $db);
			} catch (Exception $e) {
				// Defer to body
				$GLOBALS['exception'] = $e->getMessage();
			}
		}
	}

	// Send proper 404 header if we need to
	if (isset($_GET['mod']) && ($_GET['mod'] == '404' || !function_exists($_GET['mod'].'_main')))
		header("HTTP/1.0 404 Not Found");

	// Determine if we should fetch new feeds
	if (!empty($config['googlefeed']) && time() - $config['lastfetch'] >= $config['fetchfreq']) {
		$feed = array();
		$fcount = 0;
		$feed_start = microtime(true);
		$newestFetch = $db->fetchOne('SELECT `timestamp` FROM reader ORDER BY `timestamp` DESC LIMIT 1');
		try {
			$feed = Zend_Feed::import($config['googlefeed']);
		} catch (Zend_Feed_Exception $e) {
			// feed import failed
			$logger->log('Error importing feed: ' . $e->getMessage(), Zend_Log::ERR);
		} catch (Zend_Http_Client_Adapter_Exception $e) {
			$logger->log('Error connecting to feed: ' . $e->getMessage(), Zend_Log::ERR);
		}
		// Loop over each channel item and store relevant data
		foreach ($feed as $item) {
			if (dateToTimestamp($item->published()) > $newestFetch) { // Poor Logic. Fetch from last timestamp in DB but sharing an old feed will cause it to be skipped.
				$data = array();
				$feedtags = '';
				if ($feed instanceof Zend_Feed_Atom) {
					if (count($item->category) <= 1)
						$feedtags .= $item->category['term'];
					else {
						foreach ($item->category as $cat) {
							$feedtags .= $cat['term'] . ',';
						}
					}
					// Fetch the full feed if there is no summary and try to make it a summary
					$summary = $item->summary();
					if (empty($summary)) {
						// Try Google Reader style first
						$tmp = preg_split("@</blockquote>@isUu", $item->content(), 2);
						// If that doesn't seem right try more generic
						if (count($tmp) == 1) {
							$tmp = preg_split("@<br(.*)>@isUu", $item->content(), 2);
							$summary = $tmp[0];
						} else {
							$ann = preg_split("@<br(.*)>@isUu", $tmp[0]);
							$data['annotation'] = $ann[1];
							$summary = $tmp[1];
						}
					}
					// We can have more than 1 link
					if (count($item->link()) > 1)
						$data['source'] = $item->link[0]['href'];
					else
						$data['source'] = $item->link['href'];
					$data['tags']      = rtrim($feedtags,',');
					$data['timestamp'] = dateToTimestamp($item->published());
				}
				elseif ($feed instanceof Zend_Feed_Rss) {
					$summary = $item->description();
					$data['source']    = $item->link();
					$data['tags']      = $item->category();
					$data['timestamp'] = dateToTimestamp($item->pubDate(), DATE_RSS);
				}
				else
					trigger_error("Unknown feed type.  Must be valid RSS or ATOM.");
				$data['title']   = $item->title();
				$data['summary'] = cleanFeed($summary);
				// Check for existing; update if found.
				$old = $db->fetchOne('SELECT `id` FROM reader WHERE `source` = ?', $data['source']);
				if ($old)
					$db->update('reader', $data, 'id = ' . $old);
				else
					$db->insert('reader', $data);
				$fcount++;
			}
		}
		$db->update('config', array('lastfetch' => time()));
		$view->getEngine()->clear_cache('feeds.tpl');
		$feed_end = microtime(true);
		$logger->log('Fetched ' . $fcount . ' feed(s) in ' . ($feed_end - $feed_start) . ' seconds.', Zend_Log::INFO);
	}
		
	/**
	 * Insert the <title> and other tags inside the <head> tag for the requested page.
	 */
	function insert_gcmsHead() {
		global $db, $config, $translate, $headers;
		$headers->headTitle($config['sitename']);
		$headers->headTitle()->setSeparator(' - ');
		$headers->headMeta()->setName('keywords', $config['sitekeywords']);
		$headers->headMeta()->setName('author', $config['siteauthor']);
		$headers->headMeta()->setName('description', $config['sitedesc']);
		$headers->headMeta()->setName('generator', "GCMS v" . GCMS_VERSION);
		$headers->headLink()->setAlternate("feed.php?type=RSS2.0", "application/rss+xml", "RSS");
		$headers->headScript()->prependFile("./libs/mootools-1.2.4.4-more.js");
		$headers->headScript()->prependFile("./libs/mootools-1.2.4-core-yc.js");
		$headers->headScript()->appendFile("./gcms.js");
		// Call our current mod's head function and then display our HTML
		if (isset($_GET['mod']) && function_exists($_GET['mod'].'_head')) {
			try {
				call_user_func($_GET['mod'].'_head', $db, $headers, $translate);
			} catch (Exception $e) {
				// Defer to body
				$GLOBALS['exception'] = $e->getMessage();
			}
		}
		echo $headers->headTitle();
		echo $headers->headMeta();
		echo $headers->headLink();
		echo $headers->headScript();
	}

	/**
	 * Generates the main page body.
	 */
	function insert_gcmsBody() {
		global $db, $config, $view, $translate, $logger;
		if (isset($_GET['mod'])) {
			if (function_exists($_GET['mod'].'_main')) {
				// Handle all exceptions here
				try {
					if (isset($GLOBALS['exception']))
						throw new Exception($GLOBALS['exception']);
					call_user_func($_GET['mod'].'_main', $db, $view, $translate);
				} catch (Exception $e) {
					$logger->log('Exception caught: ' . $e->getMessage(), Zend_Log::ERR);
					$view->assign('message', $e->getMessage());
					$view->display('exception.tpl');
				}
			}
			else
				$view->display('error404.tpl');
		} else {
			require_once './libs/phpbb.php';
			if (!empty($config['forumdir']))
				$phpbb = new Zend_PHPBB3($config['forumdir']);
			$sticky = array();
			$feed = array();
			// First fetch our sticky posts
			$rs = $db->query("SELECT * FROM news WHERE sticky = 1 AND published = 1 ORDER BY pubdate DESC");
			while ($row = $rs->fetch()) {
				if (!empty($row['tags']))
					$row['tags'] = tag_builder($row['tags']);
				if (isset($phpbb) && $phpbb->get_approved($row['comments']))
					$row['comments'] = array('fid' => $config['forumid'], 'tid' => $row['comments'], 'count' => $phpbb->get_count($row['comments']));
				$sticky[] = $row;
			}
			$view->assign('sticky', $sticky);
			// Union our regular news posts and RSS feeds
			$rs = $db->query("(SELECT id,title,content,NULL as source,UNIX_TIMESTAMP(pubdate) as timestamp,tags,comments,NULL as annotation,'news' as type FROM news WHERE sticky = 0 AND published = 1)
			                   UNION (SELECT id,title,summary as content,source,timestamp,tags,NULL as comments,annotation,'reader' as type FROM reader) ORDER BY timestamp DESC LIMIT 5");
			while ($row = $rs->fetch()) {
				if ($row['type'] == 'reader') {
					$source = parse_url($row['source'], PHP_URL_HOST);
					$content = $row['content'] . " <a href=\"$row[source]\" target=\"_blank\">" . $translate->_("[Read More..]") . "</a>";
					$feed[] = array("id" => $row['id'], "title" => $row['title'], "source" => $source, "content" => $content, "pubdate" => $row['timestamp'], "annotation" => $row['annotation'], "tags" => tag_builder($row['tags']), "type" => $row['type']);
				} else {
					if (isset($phpbb) && $phpbb->get_approved($row['comments']))
						$row['comments'] = array('fid' => $config['forumid'], 'tid' => $row['comments'], 'count' => $phpbb->get_count($row['comments']));
					$feed[] = array("id" => $row['id'], "title" => $row['title'], "content" => $row['content'], "pubdate" => $row['timestamp'], "tags" => tag_builder($row['tags']), "type" => $row['type'], "comments" => $row['comments']);
				}
			}
			$view->assign('feed', $feed);			
			$view->display('feeds.tpl');
		}
	}
	
	/**
	 * Displays author's most recent posts.
	 *
	 * @param array $args Arguments to pass to the module in the form of an assoc array.
	 */
	function insert_gcmsMyPosts($args) {
		global $db, $view;
		if (!isset($args['count']) || !is_numeric($args['count']))
		    $args['count'] = 5;
		$first = true;
		$data = $db->fetchAll("SELECT id,title FROM news WHERE published = 1 ORDER BY pubdate DESC LIMIT " . (int)$args['count']);
		$view->assign('data', $data);
		$view->display('myposts.tpl');
	}
	
	/**
	 * Displays site syndicate images with links.
	 *
	 * @param array $args Arguments to pass to the module in the form of an assoc array.
	 */
	function insert_gcmsSyndicate($args) {
		global $view;
		$view->display('syndicate.tpl');
	}

	// Assign some variables for use in our templates
	$view->assign("gcms_theme_dir", './themes/' . $config['sitetheme']);
	$view->assign("gcms_image_url", rtrim(str_replace($_SERVER['DOCUMENT_ROOT'], '', $config['imagedir']), '/'));
	$view->assign("gcms_phpbb_url", rtrim(str_replace($_SERVER['DOCUMENT_ROOT'], '', $config['forumdir']), '/'));
	$view->assign("gcms_site_url", $config['siteURL']);
	$view->assign("gcms_site_name", $config['sitename']);
	$view->assign("gcms_site_slogan", $config['siteslogan']);
	$view->assign("gcms_site_author", $config['siteauthor']);
	$view->assign("gcms_isadmin", $authNamespace->admin);
	$view->assign("GCMS_Version", GCMS_VERSION);
	$view->assign("Zend_Version", Zend_Version::VERSION);

	$time_start = microtime(true);
	//if (extension_loaded('zlib'))
	//	ob_start("ob_gzhandler");
	//else
	//	ob_start();
	if (isset($_GET['print']) && function_exists($_GET['mod'].'_print'))
		call_user_func($_GET['mod'].'_print', $db, $view, $translate);
	else
		$view->display('main.tpl');
	//ob_end_flush();
	$time_end = microtime(true);
	$logger->log('Rendered page in ' . ($time_end - $time_start) . ' seconds.', Zend_Log::INFO);
?>
